package com.zhz.common.tool.oss.huaweicloud;

import com.obs.services.ObsClient;
import com.obs.services.model.*;
import com.zhz.common.tool.oss.OssService;
import com.zhz.common.tool.oss.huaweicloud.VO.FileUploadStatusVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.IOUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.Objects;

/**
 * 华为云上传服务
 *
 * @author Alfred
 * @create 2023/5/15
 */
@Slf4j
public class HuaweiCloudOssServiceImpl implements OssService {

    private final ObsClient obsClient;

    public HuaweiCloudOssServiceImpl(HuaweiCloudOssProperties properties) {
        checkHuaweiOssProperty(properties);
        obsClient = new ObsClient(properties.getAk(), properties.getSk(), properties.getEndPoint());
    }

    /**
     * 检查华为云配置是否为空
     *
     * @param properties 华为云配置
     */
    private static void checkHuaweiOssProperty(HuaweiCloudOssProperties properties) {
        if (Objects.isNull(properties)) {
            throw new RuntimeException("华为云OSS配置为空");
        }
        if (Objects.isNull(properties.getAk())) {
            throw new RuntimeException("华为云OSS配置ak为空");
        }
        if (Objects.isNull(properties.getSk())) {
            throw new RuntimeException("华为云OSS配置sk为空");
        }
        if (Objects.isNull(properties.getEndPoint())) {
            throw new RuntimeException("华为云OSS配置endPoint为空");
        }
    }

    /**
     * 文件上传(https://support.huaweicloud.com/sdk-java-devg-obs/obs_21_0603.html)
     *
     * @param uploadFile 上传的文件
     * @param fileName   文件名称
     * @return 返回的路径
     */
    @Override
    public String uploadFile(MultipartFile uploadFile, String fileName, String bucketName) {
        try {
            //获取文件信息
            InputStream inputStream = uploadFile.getInputStream();
            long available = inputStream.available();
            PutObjectRequest request = new PutObjectRequest(bucketName, String.valueOf(fileName), inputStream);
            ObjectMetadata objectMetadata = new ObjectMetadata();
            objectMetadata.setContentLength(available);
            request.setMetadata(objectMetadata);
            //设置公共读
            request.setAcl(AccessControlList.REST_CANNED_PUBLIC_READ);
            PutObjectResult putObjectResult = obsClient.putObject(request);
            if (Objects.isNull(putObjectResult)) {
                throw new RuntimeException("文件上传失败");
            }
            return putObjectResult.getObjectKey();
        } catch (IOException e) {
            throw new RuntimeException("文件上传失败");
        }
    }

    /**
     * 文件流上传(https://support.huaweicloud.com/sdk-java-devg-obs/obs_21_0602.html)
     *
     * @param fileName   文件名称
     * @param bucketName 桶名称
     * @param out        文件流
     * @return 返回的路径
     */
    @Override
    public String uploadFileByte(String fileName, String bucketName, byte[] out, String contentType) {
        PutObjectResult putObjectResult = obsClient.putObject(bucketName, fileName, new ByteArrayInputStream(out));
        if (Objects.isNull(putObjectResult)) {
            throw new RuntimeException("文件上传失败");
        }
        return putObjectResult.getObjectKey();
    }


    /**
     * 获取文件上传进度
     *
     * @param fileName 文件名称
     * @return 返回文件上传进度
     */
    @Override
    public FileUploadStatusVO getFileUploadPlan(String fileName, String bucketName) {
        FileUploadStatusVO fileUploadStatus = new FileUploadStatusVO();
        try {
            GetObjectRequest request = new GetObjectRequest(bucketName, fileName);
            request.setProgressListener(new ProgressListener() {
                @Override
                public void progressChanged(ProgressStatus status) {
                    //上传的平均速度
                    fileUploadStatus.setAvgSpeed(status.getAverageSpeed());
                    //上传的百分比
                    fileUploadStatus.setPct(String.valueOf(status.getTransferPercentage()));
                }
            });
            // 每下载1MB数据反馈下载进度
            request.setProgressInterval(1024 * 1024L);
            ObsObject obsObject = obsClient.getObject(request);
            // 读取对象内容
            InputStream input = obsObject.getObjectContent();
            byte[] b = new byte[1024];
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            int len;
            while ((len = input.read(b)) != -1) {
                //将每一次的数据写入缓冲区
                byteArrayOutputStream.write(b, 0, len);
            }
            byteArrayOutputStream.close();
            input.close();
            return fileUploadStatus;
        } catch (Exception e) {
            throw new RuntimeException("获取文件上传进度失败");
        }
    }

    /**
     * 文件下载
     *
     * @param response 响应
     * @param fileName 文件名称
     * @return
     */
    @Override
    public void fileDownload(HttpServletResponse response, String fileName, String bucketName) {
        try {
            ObsObject obsObject = obsClient.getObject(bucketName, fileName);
            InputStream input = obsObject.getObjectContent();
            //缓冲文件输出流
            BufferedOutputStream outputStream = new BufferedOutputStream(response.getOutputStream());
            //设置让浏览器弹出下载提示框，而不是直接在浏览器中打开
            response.addHeader("Content-Disposition", "attachment;filename=" + fileName);
            IOUtils.copy(input, outputStream);
            outputStream.flush();
            outputStream.close();
            input.close();
        } catch (Exception e) {
            throw new RuntimeException("文件下载失败");
        }
    }

    /**
     * 删除文件
     *
     * @param fileName   文件名称
     * @param bucketName 桶名称
     */
    @Override
    public void deleteFile(String fileName, String bucketName) {
        try {
            obsClient.deleteObject(bucketName, fileName);
        } catch (Exception e) {
            throw new RuntimeException("文件删除失败");
        }
    }
}
